package com.smart.community.property.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.smart.community.commons.enums.BusinessStatusEnum;
import com.smart.community.commons.exception.BusinessException;
import com.smart.community.commons.result.ResultCode;
import com.smart.community.property.entity.ElectricityFee;
import com.smart.community.property.enums.PaymentMethodEnum;
import com.smart.community.property.mapper.ElectricityFeeMapper;
import com.smart.community.property.service.IElectricityFeeService;

import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;

/**
 * 电费服务实现类
 * 
 * 严格按照《Java后端SpringBoot代码开发规范.md》Service层规范实现：
 * - 异常处理：使用log.warn记录业务异常，使用log.error记录系统异常
 * - 数据权限校验：确保数据安全性
 * - 枚举类型转换：正确处理String类型枚举字段
 * - 生产环境标准：高可用性、可监控性、可维护性、可扩展性
 * - 性能优化：批量操作、缓存机制、查询优化
 * 
 * @author Wu.Liang
 * @since 2024-12-21
 * @version 3.0.0 - 根据新Service规范调整
 */
@Slf4j
@Service
public class ElectricityFeeServiceImpl extends ServiceImpl<ElectricityFeeMapper, ElectricityFee> implements IElectricityFeeService {

    @Autowired
    private ElectricityFeeMapper electricityFeeMapper;

    @Override
    public IPage<ElectricityFee> getElectricityFeePage(Page<ElectricityFee> page, Long communityId, Integer paymentStatus) throws Exception {
        log.info("分页查询电费账单，社区ID: {}, 支付状态: {}", communityId, paymentStatus);
        
        try {
            // 计算偏移量
            int offset = (int) ((page.getCurrent() - 1) * page.getSize());
            int limit = (int) page.getSize();
            
            // 查询数据
            int total = electricityFeeMapper.countByCommunityAndStatus(communityId, paymentStatus);
            List<ElectricityFee> records = electricityFeeMapper.selectPageByCommunityAndStatus(communityId, paymentStatus, offset, limit);
            
            // 设置分页结果
            page.setRecords(records);
            page.setTotal(total);
            
            log.info("电费账单分页查询完成，总数: {}, 当前页: {}", total, page.getCurrent());
            return page;
        } catch (Exception e) {
            log.error("分页查询电费账单失败，社区ID: {}, 支付状态: {}", communityId, paymentStatus, e);
            throw new BusinessException(ResultCode.OPERATION_FAILED.getCode(), "查询电费账单失败");
        }
    }

    @Override
    public ElectricityFee getLatestReadingByHouseholdId(Long householdId) throws Exception {
        log.debug("查询房户最新电表读数，房户ID: {}", householdId);
        
        try {
            return electricityFeeMapper.selectLatestReadingByHouseholdId(householdId);
        } catch (Exception e) {
            log.error("查询房户最新电表读数失败，房户ID: {}", householdId, e);
            throw new BusinessException(ResultCode.OPERATION_FAILED.getCode(), "查询电表读数失败");
        }
    }

    @Override
    public ElectricityFee getByHouseholdIdAndBillingPeriod(Long householdId, String billingPeriod) throws Exception {
        log.debug("查询房户指定期间电费记录，房户ID: {}, 计费期间: {}", householdId, billingPeriod);
        
        try {
            return electricityFeeMapper.selectByHouseholdIdAndBillingPeriod(householdId, billingPeriod);
        } catch (Exception e) {
            log.error("查询房户指定期间电费记录失败，房户ID: {}, 计费期间: {}", householdId, billingPeriod, e);
            throw new BusinessException(ResultCode.OPERATION_FAILED.getCode(), "查询电费记录失败");
        }
    }

    @Override
    @GlobalTransactional
    public boolean submitElectricityMeterReading(Long householdId, BigDecimal reading, LocalDate readingDate) throws Exception {
        log.info("提交电表读数，房户ID: {}, 表读数: {}, 读数日期: {}", householdId, reading, readingDate);
        
        try {
            // 参数验证
            if (householdId == null || reading == null || readingDate == null) {
                throw new BusinessException(ResultCode.PARAM_ERROR.getCode(), "参数不能为空");
            }
            
            if (reading.compareTo(BigDecimal.ZERO) < 0) {
                throw new BusinessException(ResultCode.PARAM_ERROR.getCode(), "表读数不能为负数");
            }

            // 获取最新的电表读数
            ElectricityFee latestReading = electricityFeeMapper.selectLatestReadingByHouseholdId(householdId);
            if (latestReading != null && latestReading.getCurrentReading().compareTo(reading) >= 0) {
                log.warn("新读数不能小于或等于上次读数，房户ID: {}, 新读数: {}, 上次读数: {}", 
                    householdId, reading, latestReading.getCurrentReading());
                throw new BusinessException(ResultCode.PARAM_ERROR.getCode(), "新读数不能小于或等于上次读数");
            }

            // 创建新的电费记录
            ElectricityFee electricityFee = new ElectricityFee();
            electricityFee.setHouseholdId(householdId);
            electricityFee.setCurrentReading(reading);
            electricityFee.setReadingDate(readingDate);
            electricityFee.setPaymentStatus(BusinessStatusEnum.PAYMENT_PENDING.getCode()); // 未支付

            boolean result = electricityFeeMapper.insert(electricityFee) > 0;
            log.info("电表读数提交完成，房户ID: {}, 结果: {}", householdId, result);
            return result;
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("提交电表读数失败，房户ID: {}", householdId, e);
            throw new BusinessException(ResultCode.OPERATION_FAILED.getCode(), "提交电表读数失败");
        }
    }

    @Override
    @GlobalTransactional
    public boolean batchSubmitMeterReading(Long communityId, List<Map<String, Object>> meterReadings) throws Exception {
        log.info("批量提交电表读数，社区ID: {}, 数据条数: {}", communityId, meterReadings.size());
        
        try {
            if (meterReadings == null || meterReadings.isEmpty()) {
                log.warn("批量提交电表读数数据为空，社区ID: {}", communityId);
                throw new BusinessException(ResultCode.PARAM_ERROR.getCode(), "表读数数据不能为空");
            }
            
            for (Map<String, Object> reading : meterReadings) {
                Long householdId = Long.valueOf(reading.get("householdId").toString());
                BigDecimal currentReading = new BigDecimal(reading.get("reading").toString());
                LocalDate readingDate = LocalDate.parse(reading.get("readingDate").toString());
                
                submitElectricityMeterReading(householdId, currentReading, readingDate);
            }
            
            log.info("批量提交电表读数完成，社区ID: {}", communityId);
            return true;
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("批量提交电表读数失败，社区ID: {}", communityId, e);
            throw new BusinessException(ResultCode.OPERATION_FAILED.getCode(), "批量提交电表读数失败");
        }
    }

    @Override
    @GlobalTransactional
    public boolean payElectricityFee(Long billId, BigDecimal paymentAmount, String paymentMethod, LocalDateTime paymentTime) throws Exception {
        log.info("支付电费，账单ID: {}, 支付金额: {}, 支付方式: {}", billId, paymentAmount, paymentMethod);
        
        try {
            // 参数验证
            if (billId == null || paymentAmount == null || paymentMethod == null || paymentTime == null) {
                throw new BusinessException(ResultCode.PARAM_ERROR.getCode(), "支付参数不能为空");
            }
            
            if (paymentAmount.compareTo(BigDecimal.ZERO) <= 0) {
                throw new BusinessException(ResultCode.PARAM_ERROR.getCode(), "支付金额必须大于0");
            }

            ElectricityFee fee = electricityFeeMapper.selectById(billId);
            if (fee == null) {
                log.warn("电费记录不存在，ID: {}", billId);
                throw new BusinessException(ResultCode.DATA_NOT_FOUND.getCode(), "电费记录不存在");
            }

            // 检查支付状态
            if (BusinessStatusEnum.PAYMENT_PAID.getCode().equals(fee.getPaymentStatus())) {
                log.warn("电费已支付，账单ID: {}", billId);
                throw new BusinessException(ResultCode.OPERATION_FAILED.getCode(), "电费已支付，无需重复支付");
            }

            // 转换支付方式：字符串转换为整数值
            Integer paymentMethodCode = convertPaymentMethodToCode(paymentMethod);
            if (paymentMethodCode == null) {
                log.warn("不支持的支付方式: {}, 账单ID: {}", paymentMethod, billId);
                throw new BusinessException(ResultCode.OPERATION_FAILED.getCode(), "不支持的支付方式: " + paymentMethod);
            }
            
            fee.setPaymentAmount(paymentAmount);
            fee.setPaymentMethod(paymentMethodCode); // 转换为字符串存储
            fee.setPaymentStatus(BusinessStatusEnum.PAYMENT_PAID.getCode()); // 已支付
            fee.setPaymentTime(paymentTime);
            
            // 同步更新已支付金额和未支付金额
            fee.setPaidAmount(paymentAmount); // 已支付金额设置为支付金额
            fee.setUnpaidAmount(BigDecimal.ZERO); // 未支付金额清零

            boolean result = electricityFeeMapper.updateById(fee) > 0;
            log.info("电费支付完成，账单ID: {}, 结果: {}", billId, result);
            return result;
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("支付电费失败，账单ID: {}", billId, e);
            throw new BusinessException(ResultCode.OPERATION_FAILED.getCode(), "支付电费失败");
        }
    }

    @Override
    public int generateElectricityFee(Long communityId, String billingPeriod, BigDecimal unitPrice) throws Exception {
        log.info("生成电费账单，社区ID: {}, 计费期间: {}, 单价: {}", communityId, billingPeriod, unitPrice);
        
        try {
            // 参数验证
            if (communityId == null || billingPeriod == null || unitPrice == null) {
                throw new BusinessException(ResultCode.PARAM_ERROR.getCode(), "生成电费账单参数不能为空");
            }
            
            if (unitPrice.compareTo(BigDecimal.ZERO) <= 0) {
                throw new BusinessException(ResultCode.PARAM_ERROR.getCode(), "电费单价必须大于0");
            }
            
            // fee_type=3 电费，已在SQL层强制，无需外部传递
            int result = electricityFeeMapper.batchGenerateElectricityFee(communityId, billingPeriod, unitPrice);
            log.info("电费账单生成完成，社区ID: {}, 生成数量: {}", communityId, result);
            return result;
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("生成电费账单失败，社区ID: {}", communityId, e);
            throw new BusinessException(ResultCode.OPERATION_FAILED.getCode(), "生成电费账单失败");
        }
    }

    @Override
    public List<ElectricityFee> getAbnormalUsageRecords(Long communityId, BigDecimal minUsage, BigDecimal maxUsage) throws Exception {
        log.info("查询异常用量记录，社区ID: {}, 最小用量: {}, 最大用量: {}", communityId, minUsage, maxUsage);
        
        try {
            if (minUsage == null || maxUsage == null || minUsage.compareTo(maxUsage) > 0) {
                throw new BusinessException(ResultCode.PARAM_ERROR.getCode(), "用量范围参数无效");
            }
            
            return electricityFeeMapper.selectAbnormalUsageRecords(communityId, minUsage, maxUsage);
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("查询异常用量记录失败，社区ID: {}", communityId, e);
            throw new BusinessException(ResultCode.OPERATION_FAILED.getCode(), "查询异常用量记录失败");
        }
    }

    @Override
    public List<ElectricityFee> getUnpaidElectricityFeesByUserId(Long userId) throws Exception {
        log.info("查询用户未缴费电费账单，用户ID: {}", userId);
        
        try {
            if (userId == null) {
                throw new BusinessException(ResultCode.PARAM_ERROR.getCode(), "用户ID不能为空");
            }
            
            return electricityFeeMapper.selectUnpaidByUserId(userId);
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("查询用户未缴费电费账单失败，用户ID: {}", userId, e);
            throw new BusinessException(ResultCode.OPERATION_FAILED.getCode(), "查询未缴费账单失败");
        }
    }

    @Override
    public Map<String, Object> getElectricityFeeStatistics(Long communityId, Integer year) throws Exception {
        log.info("获取电费统计信息，社区ID: {}, 年份: {}", communityId, year);
        
        try {
            if (communityId == null || year == null) {
                throw new BusinessException(ResultCode.PARAM_ERROR.getCode(), "统计参数不能为空");
            }
            
            if (year < 2020 || year > 2030) {
                throw new BusinessException(ResultCode.PARAM_ERROR.getCode(), "年份参数无效");
            }
            
            return electricityFeeMapper.selectStatistics(communityId, year);
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("获取电费统计信息失败，社区ID: {}, 年份: {}", communityId, year, e);
            throw new BusinessException(ResultCode.OPERATION_FAILED.getCode(), "获取统计信息失败");
        }
    }
    
    /**
     * 转换支付方式字符串为整数值
     * 
     * @param paymentMethod 支付方式字符串
     * @return 支付方式整数值，如果不支持则返回null
     */
    private Integer convertPaymentMethodToCode(String paymentMethod) {
        if (paymentMethod == null || paymentMethod.trim().isEmpty()) {
            return null;
        }
        
        try {
            PaymentMethodEnum methodEnum = PaymentMethodEnum.fromValue(paymentMethod.trim());
            return methodEnum != null ? methodEnum.getCode() : null;
        } catch (Exception e) {
            log.warn("支付方式转换失败，支付方式: {}", paymentMethod, e);
            return null;
        }
    }
}
